package com.market.dao.hibernate;

import java.io.Serializable;
import java.sql.Connection;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;
import org.springframework.orm.ObjectRetrievalFailureException;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.market.dao.GenericDao;

/**
 * This class serves as the Base class for all other DAOs - namely to hold
 * common CRUD methods that they might all use. You should only need to extend
 * this class when your require custom CRUD logic.
 *
 * <p>To register this class in your Spring context file, use the following XML.
 * <pre>
 *      &lt;bean id="fooDao" class="com.phevos.bugtrace.dao.hibernate.GenericDaoHibernate"&gt;
 *          &lt;constructor-arg value="com.phevos.bugtrace.model.Foo"/&gt;
 *          &lt;property name="sessionFactory" ref="sessionFactory"/&gt;
 *      &lt;/bean&gt;
 * </pre>
 *
 * @author <a href="mailto:bwnoll@gmail.com">Bryan Noll</a>
 * @param <T> a type variable
 * @param <PK> the primary key for that type
 */
public class GenericDaoHibernate<T, PK extends Serializable> extends HibernateDaoSupport implements GenericDao<T, PK> {
    /**
     * Log variable for all child classes. Uses LogFactory.getLog(getClass()) from Commons Logging
     */
    protected final Log log = LogFactory.getLog(getClass());
    private Class<T> persistentClass;

    /**
     * Constructor that takes in a class to see which type of entity to persist
     * @param persistentClass the class type you'd like to persist
     */
    public GenericDaoHibernate(final Class<T> persistentClass) {
        this.persistentClass = persistentClass;
    }

    public GenericDaoHibernate()
    {
        
    }
    /**
     * {@inheritDoc}
     */
    @SuppressWarnings("unchecked")
    public List<T> getAll() {
        return super.getHibernateTemplate().loadAll(this.persistentClass);
    }

    /**
     * {@inheritDoc}
     */
    @SuppressWarnings("unchecked")
    public T get(PK id) {
        T entity = (T) super.getHibernateTemplate().get(this.persistentClass, id);

        if (entity == null) {
            log.warn("Uh oh, '" + this.persistentClass + "' object with id '" + id + "' not found...");
            throw new ObjectRetrievalFailureException(this.persistentClass, id);
        }

        return entity;
    }

    /**
     * {@inheritDoc}
     */
    @SuppressWarnings("unchecked")
    public boolean exists(PK id) {
        T entity = (T) super.getHibernateTemplate().get(this.persistentClass, id);
        return entity != null;
    }

    /**
     * {@inheritDoc}
     */
    @SuppressWarnings("unchecked")
    public T save(T object) {
        return (T) super.getHibernateTemplate().merge(object);
    }

    /**
     * {@inheritDoc}
     */
    public void remove(PK id) {
        super.getHibernateTemplate().delete(this.get(id));
    }
    
    public void saveOrUpdate(Object obj)
    {
        log.debug("obj is"+obj.toString());
        log.debug("saving object instance");
        
        if(obj==null)
        {
            return;
        }
        
       
        try
        {
            getHibernateTemplate().saveOrUpdate(obj);
            log.debug("save successful");
        }
        catch (RuntimeException re)
        {
            log.error("save failed", re);
            throw re;
        }
    }

    public void delete(Object obj)
    {
        log.debug("deleting object instance");
        try
        {
            getHibernateTemplate().delete(obj);
            log.debug("delete successful");
        }
        catch (RuntimeException re)
        {
            log.error("delete failed", re);
            throw re;
        }
    }

    public List findByDetchedCriteria(DetachedCriteria detachCri, int start, int max)
    {
        if (max != 0)
        {
            return getHibernateTemplate().findByCriteria(detachCri, start, max);
        }
        else
        {
            return getHibernateTemplate().findByCriteria(detachCri);
        }
    }
    
    public int getCountByDetachedCriteria(DetachedCriteria detachCri)
    {
        detachCri.setProjection(Projections.rowCount());
        List l = getHibernateTemplate().findByCriteria(detachCri);
        if (!l.isEmpty())
        {
            return ((Integer)l.get(0)).intValue();
        }
        else
        {
            return 0;
        }
    }

    public void deleteByDetachedCriteria(DetachedCriteria detachCri)
    {
        getHibernateTemplate().deleteAll(getHibernateTemplate().findByCriteria(detachCri));

    }
    
    public Connection getConnection()
    {
        return getSession().connection();
    }
}
